﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using QLTT.Models;
using QLTT.Commands;
using System.Windows.Input;
using QLTT.Properties;

namespace QLTT.ViewModels
{
    class ClassViewModel : WorkspaceViewModel, System.ComponentModel.IDataErrorInfo
    {
        private Class _class;
        private icanDataContext _dataContext;
        private DelegateCommand _saveCommand;
        private DelegateCommand _editCommand;
        private DelegateCommand _cancelCommand;
        private DelegateCommand _selectScheduleCommand;
        private List<ScheduleViewModel> _lstSchedule;
        private bool _isSelected;
        public ClassViewModel(icanDataContext dataContext)
        {
            _dataContext = dataContext;
            _class = new Class();
            _class.StartDate = DateTime.Today.AddDays(10);
            _class.EndDate = DateTime.Today.AddDays(40);
            base.DisplayName = Properties.Resources.Base_DisplayName_Class_New;
        }
        
        public ClassViewModel(icanDataContext dataContext, Class oClass)
        {
            _class = oClass;
            _dataContext = dataContext;
            base.DisplayName = Properties.Resources.Base_DisplayName_Class_Edit;
        }
        public ICommand SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                {
                    _saveCommand = new DelegateCommand(Save);
                }
                return _saveCommand;
            }
        }
        public ICommand EditCommand
        {
            get
            {
                if (_editCommand == null)
                {
                    _editCommand = new DelegateCommand(Edit);
                }
                return _editCommand;
            }
        }
        public ICommand CancelCommand
        {
            get
            {
                if (_cancelCommand == null)
                {
                    _cancelCommand = new DelegateCommand(Cancel);
                }
                return _cancelCommand;
            }
        }
        public ICommand SelectScheduleCommand
        {
            get
            {
                if (_selectScheduleCommand == null)
                {
                    _selectScheduleCommand = new DelegateCommand(SelectSchedule);
                }
                return _selectScheduleCommand;
            }
        }
        public bool CanDelete()
        {
            return _class.StudentClasses.Count == 0;
        }

        private void Save()
        {
            if (_dataContext == null || _class == null)
                return;
            try
            {
                string[] properties = { "Name", "Level", "StartDate", "EndDate", "Room", "Fee" , "MaxStudent" };
                if (!ValidateData(properties))
                    return;
                bool isInsert = _class.ID == 0;
                _class.LastUpdated = DateTime.Now;
                if (isInsert)
                {
                    _dataContext.Classes.InsertOnSubmit(_class);

                }
                _dataContext.SubmitChanges();
                this.OnPropertyChanged("ID"); //Update ClassViewModel ID
                if (isInsert)
                {
                    foreach (ScheduleViewModel sVM in this.Schedules)
                    {
                        sVM.Class = this;
                        sVM.Save();
                    }
                    Mediator.NotifyColleagues<Class>(Messages.ListClassUpdated, _class);
                }
                Mediator.NotifyColleagues<WorkspaceViewModel>(Messages.WorkspaceRemove, this);
            }
            catch (Exception ex)
            {
                this.ErrorMsg = Properties.Resources.ErrorMessage_General;
                System.Diagnostics.EventLog.WriteEntry("Application", ex.ToString(), System.Diagnostics.EventLogEntryType.Error);
            }
            
            
        }
        private void Edit()
        {
            if (_dataContext == null || _class == null)
                return;
            
            Mediator.NotifyColleagues<WorkspaceViewModel>(Messages.WorkspaceAdd, this);
        }
        private void Cancel()
        {
            if(_class.ID > 0)
                _dataContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, _class);
            Mediator.NotifyColleagues<WorkspaceViewModel>(Messages.WorkspaceRemove, this);
        }
        public void Delete()
        {
            if (_dataContext == null || _class == null)
                return;
            try
            {
                _dataContext.Schedules.DeleteAllOnSubmit(_class.Schedules);
                _dataContext.FeePayments.DeleteAllOnSubmit(_class.FeePayments);
                _dataContext.Classes.DeleteOnSubmit(_class);
                _dataContext.SubmitChanges();
            }
            catch(Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("Application", ex.ToString(), System.Diagnostics.EventLogEntryType.Error);
            }
        }
        public void SelectSchedule()
        {
            AllScheduleViewModel sVM = new AllScheduleViewModel(this, _dataContext);
            Mediator.NotifyColleagues<WorkspaceViewModel>(Messages.WorkspaceAdd, sVM);
        }
        [MediatorLib.MediatorMessageSink(Messages.ListScheduleUpdated, ParameterType = typeof(List<ScheduleViewModel>))]
        public void UpdateSchedule(List<ScheduleViewModel> lstSVM)
        {
            this.OnPropertyChanged("ScheduleDisplayText");
            this.OnPropertyChanged("Rooms");
        }
        public long ID
        {
            get { return _class.ID; }
        }

        public string Name
        {
            get { return _class.Name; }
            set
            {
                if (_class.Name == value) return;
                _class.Name = value;
                base.OnPropertyChanged("Name");
            }
        }
        public long Level
        {
            get { return _class.Level; }
            set
            {
                if (_class.Level == value) return;
                _class.Level = value;
                base.OnPropertyChanged("Level");
            }
        }
        public string LevelName
        {
            get { return _class.Level1.Name; }
        }
        
        public long Room
        {
            get { return _class.Room; }
            set
            {
                if (_class.Room == value) return;
                _class.Room = value;
                Room r = _dataContext.Rooms.Where(o => o.ID == _class.Room).Select(o => o).FirstOrDefault();
                this.MaxStudent = r.Capacity;
                base.OnPropertyChanged("MaxStudent");
                base.OnPropertyChanged("Room");
            }
        }
        public string RoomName
        {
            get { return _class.Room1.Name; }
            
        }
        public DateTime StartDate
        {
            get { return _class.StartDate; }
            set
            {
                if (_class.StartDate == value) return;
                _class.StartDate = value;
                base.OnPropertyChanged("StartDate");
                base.OnPropertyChanged("EndDate");
            }
        }
        public DateTime EndDate
        {
            get { return _class.EndDate; }
            set
            {
                if (_class.EndDate == value) return;
                _class.EndDate = value;
                base.OnPropertyChanged("EndDate");
                base.OnPropertyChanged("StartDate");
            }
        }
        public System.Nullable<short> MaxStudent
        {
            get { return _class.MaxStudent.Value; }
            set
            {
                if (_class.MaxStudent == value) return;
                _class.MaxStudent = value;
                base.OnPropertyChanged("MaxStudent");
            }
        }
        public string NumberStudent
        {
            get
            {
                int numStudent = _dataContext.StudentClasses.Where(s => s.Class == _class.ID).Count();
                if (_class.MaxStudent != null)
                    return string.Format("{0}/{1}", numStudent, _class.MaxStudent);
                return numStudent.ToString();
            }
        }
        public DateTime LastUpdated
        {
            get { return _class.LastUpdated.Value; }
            set
            {
                if (_class.LastUpdated.Value == value) return;
                _class.LastUpdated = value;
                base.OnPropertyChanged("LastUpdated");
            }
        }
        public double Fee
        {
            get { return _class.Fee; }
            set
            {
                if (_class.Fee == value) return;
                _class.Fee = value;
                base.OnPropertyChanged("Fee");
            }
        }

        public List<StudentClass> StudentClasses	
        {
            get { return _class.StudentClasses.ToList(); }
            
        }
        public List<FeePayment> FeePayments
        {
            get { return _class.FeePayments.ToList(); }

        }
       
        public List<ScheduleViewModel> Schedules
        {
            get
            {
                if (_lstSchedule != null)
                    return _lstSchedule;
                List<Schedule> lstSchedule = _class.Schedules.ToList();
                _lstSchedule = new List<ScheduleViewModel>();
                foreach (Schedule schedule in lstSchedule)
                    _lstSchedule.Add(new ScheduleViewModel(schedule, _dataContext));

                return _lstSchedule;
            }
        }
        
        public bool IsSelected
        {
            get { return _isSelected; }
            set
            {
                if (value == _isSelected)
                    return;

                _isSelected = value;

                base.OnPropertyChanged("IsSelected");
                if(value==true)
                    Mediator.NotifyColleagues<WorkspaceViewModel>(Messages.ClassSelectedChanged, this);
            }
        }
        public string ScheduleDisplayText
        {
            get 
            {
                List<List<ScheduleViewModel>> lstScheduleViewModels = new List<List<ScheduleViewModel>>();
                long prevClassTime = -1;
                foreach (ScheduleViewModel sVM in this.Schedules)
                {
                    if (sVM.ClassTime.ID != prevClassTime)
                    {
                        List<ScheduleViewModel> sVMs = new List<ScheduleViewModel>();
                        sVMs.Add(sVM);
                        lstScheduleViewModels.Add(sVMs);
                        prevClassTime = sVM.ClassTime.ID;
                    }
                    else
                        lstScheduleViewModels[lstScheduleViewModels.Count - 1].Add(sVM);
                }
                //formulate the string
                List<string> classTimeStrings = new List<string>();
                foreach (List<ScheduleViewModel> lstScheduleViewModel in lstScheduleViewModels)
                {
                    List<string> dOWs = new List<string>();
                    foreach (ScheduleViewModel sVM in lstScheduleViewModel)
                    {
                        dOWs.Add(ViewModelBase.DayOfWeeks[sVM.DayOfWeek]);
                    }
                    classTimeStrings.Add(string.Format("{0} {1}", string.Join(",", dOWs.ToArray()), lstScheduleViewModel[0].FullName));
                }
                return string.Join("; ", classTimeStrings.ToArray());
            }
        }
        /* List Level for Level Combobox*/
        public List<LevelViewModel> Levels
        {
            get
            {
                List<LevelViewModel> lstLevel = _dataContext.Levels.Select(lv => new LevelViewModel(_dataContext, lv)).ToList();
                return lstLevel;
            }
        }
        /* List Room for Room Combobox*/
        public List<RoomViewModel> Rooms
        {
            get
            {
                if (this.Schedules.Count == 0)
                {
                    List<RoomViewModel> lstRoom = _dataContext.Rooms.Select(r => new RoomViewModel(_dataContext, r)).ToList();
                    return lstRoom;
                }
                //get list class at the same date range
                var query = _dataContext.Classes.Where(c => (c.StartDate >= this.StartDate && c.StartDate <= this.EndDate)
                    || (c.EndDate>=this.StartDate && this.EndDate<= this.EndDate)
                    || (c.StartDate<=this.StartDate && c.EndDate >= this.EndDate));
                List<long> lstClasses = query.Select(c => c.ID).ToList();
                //get classes have same schedule
                var query1 = _dataContext.Schedules.Where(q => 1==1);
                foreach (ScheduleViewModel sVM in this.Schedules)
                {
                    //query1 = query1.Where(s => s.DayOfWeek == sVM.DayOfWeek && ((TimeToNumber(s.ClassTime1.StartTime) > TimeToNumber(sVM.ClassTime.StartTime) && TimeToNumber(s.ClassTime1.StartTime) <= TimeToNumber(sVM.ClassTime.EndTime))
                    //    || (TimeToNumber(s.ClassTime1.EndTime) >= TimeToNumber(sVM.ClassTime.StartTime) && TimeToNumber(s.ClassTime1.EndTime) <= TimeToNumber(sVM.ClassTime.EndTime))
                    //    || (TimeToNumber(s.ClassTime1.StartTime) <= TimeToNumber(sVM.ClassTime.StartTime) && TimeToNumber(s.ClassTime1.EndTime) >= TimeToNumber(sVM.ClassTime.EndTime))));
                    query1 = query1.Where(s => s.DayOfWeek == sVM.DayOfWeek && s.ClassTime == sVM.ClassTime.ID);
                }
                List<long> lstClasses1 = query1.Select(s => s.Class).ToList();
                lstClasses = lstClasses.Where(id => lstClasses1.Contains(id) && id!=this.ID).ToList();
                List<long> lstUsedRooms = _dataContext.Classes.Where(c => lstClasses.Contains(c.ID)).Select(c => c.Room).ToList();
                List<RoomViewModel> lstRVM = _dataContext.Rooms.Where(r => !lstUsedRooms.Contains(r.ID)).Select(r => new RoomViewModel(_dataContext, r)).ToList();
                return lstRVM;
            }
        }
        
        /* Private Helpers*/
        #region Priave Helpers
        private int TimeToNumber(string time)
        {
            string[] numParts = time.Split(':');
            return int.Parse(numParts[0]) * 60 + int.Parse(numParts[1]);
        }
        #endregion
        #region IDataErrorInfo Members

        public string Error
        {
            get { return null; }
        }

        public string this[string property]
        {
            get
            {
                string msg = null;
                switch (property)
                {
                    case "Name":
                        if (string.IsNullOrEmpty(this.Name))
                            msg = Resources.ValidationClassName_Error;
                        break;
                    case "Level":
                        if (this.Level == 0) //null
                            msg = Resources.ValidationClassLevel_Error;
                        break;
                    case "Room":
                        if (this.Room == 0) //null
                            msg = Resources.ValidationClassRoom_Error;
                        break;
                    case "MaxStudent":
                        if (this.MaxStudent != null && this.MaxStudent <= 0)
                            msg = Resources.ValidationClassMaxStudent_Error;
                        break;
                    case "StartDate":
                        if (this.StartDate > this.EndDate)
                            msg = Resources.ValidationClassStartDate_Error;
                        break;
                    case "EndDate":
                        if (this.StartDate > this.EndDate)
                            msg = Resources.ValidationClassStartDate_Error;
                        break;
                    case "Fee":
                        if (this.Fee <= 0)
                            msg = Resources.ValidationClassFee_Error;
                        break;
                    default:
                        throw new ArgumentException(
                            Resources.ValidationDefaultException_Error + property);
                }
                return msg;
            }
        }

        #endregion // IDataErrorInfo Members

    }
}

